import socket, sys, select, thread, StringIO
from urlproxy_client_conf import *

max_idling = 60

def output_http_header(data):
    pass
#   open("log.txt", "a").write(data)
#    out = StringIO.StringIO(data)
#    line = out.readline().strip()
#    while line:
#        print line
#        line = out.readline().strip()
#    print "-" * 72

def Readline(sock):
    line = ''
    b = sock.recv(1)
    while b:
        line += b
        if line.rfind('\r\n', -2) != -1:
            return line
        b = sock.recv(1)

    return line


def ChunkedReceiver(rs, ws, close = False):
    count = 0
    iw = [rs,]
    ow = []
    ew = [rs, ws]
    total_len = 0
    try:
        while 1:
            count += 1
            rd, wr, ex = select.select(iw, ow, ew, 1)
            if ex: break
            for fd in rd:
                line = Readline(fd).strip()
                if not line:
                    break
                chunk_len = int(line, 16)
                #print "chunk: %d" % chunk_len
                if not chunk_len:
                    return total_len
                total_len += chunk_len
                size = 0
                data = ''
                while size < chunk_len:
                    data += fd.recv(1)
                    size += 1

                fd.recv(2) # '\r\n'

                if data:
                    #sys.stdout.write(all)
                    ws.send(data)
                    count = 0
            if count == max_idling: break
    except:
        print sys.exc_info()
    finally:
        if close:
            rs.close()
            ws.close()
    return total_len

def DirectReceiver(rs, ws, close = False):
    count = 0
    iw = [rs,]
    ow = []
    ew = [rs, ws]
    total_len = 0
    try:
        while 1:
            count += 1
            rd, wr, ex = select.select(iw, ow, ew, 1)
            if ex: break
            for fd in rd:
                all = fd.recv(4096)
                if all:
                    total_len += len(all)
                    #sys.stdout.write(all)
                    ws.send(all)
                    count = 0
            if count == max_idling: break
    except:
        print sys.exc_info()
    finally:
        if close:
            rs.close()
            ws.close()
    return total_len


def ReceiveHeaders(s):
    headers = ''
    iw = [s,]
    ow = []
    count = 0
    while 1:
        rs, ws, es = select.select(iw, ow, iw, 1)
        if es:
            break
        if rs:
            count = 0
            b = s.recv(1)
            headers += b
            if headers.rfind('\r\n\r\n', -4) != -1:
                break
        count += 1
        if count > 60:
            break

    receiver = DirectReceiver
    if headers.find('Transfer-Encoding: chunked') != -1:
        receiver = ChunkedReceiver
    return (headers, receiver)


def Http_Redir2(local):
    conn, addr = local
    out = StringIO.StringIO()
    data = conn.recv(4096)
    out.write(data)
    while len(data) == 4096:
        data = conn.recv(4096)
        out.write(data)

    data = out.getvalue()
    line = data[:data.find('\r\n')]
    print line.split()[1]

    redir_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #redir_sock.connect(('localhost', 80))
    redir_sock.connect(urlproxy_server[:2])
    redir_sock.send('POST ' + urlproxy_server[2] + ' HTTP/1.1\r\n')
    redir_sock.send('Host: localhost\r\n')
    redir_sock.send('Accept: */*\r\n')
    redir_sock.send('Content-Length: %d\r\n' % len(data))
    redir_sock.send('Connection: close\r\n') 
    redir_sock.send('\r\n')
    redir_sock.send(data)

    try:
        headers, receiver = ReceiveHeaders(redir_sock)
        nlen = receiver(redir_sock, conn, close = False)
        #print "%d bytes received." % nlen
    except:
        print sys.exc_info()
    finally:
        conn.close()
        redir_sock.close()


def Http_Redir(local):
    conn, addr = local
    out = StringIO.StringIO()
    data = conn.recv(4096)
    out.write(data)
    while len(data) == 4096:
        data = conn.recv(4096)
        out.write(data)

    data = out.getvalue()
    #print 'data:\n', data

    redir_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    redir_sock.connect(urlproxy_server[:2])
    redir_sock.send('POST ' + urlproxy_server[2] + ' HTTP/1.1\r\n')
    redir_sock.send('Host: localhost\r\n')
    redir_sock.send('Accept: */*\r\n')
    redir_sock.send('Content-Length: %d\r\n' % len(data))
    redir_sock.send('Connection: close\r\n') 
    redir_sock.send('\r\n')
    redir_sock.send(data)

    count = 0
    iw = [redir_sock,]
    ow = []
    ew = [redir_sock, conn]
    try:
        headers, receiver = ReceiveHeaders(redir_sock)
        sys.stdout.write(headers)
        while 1:
            count += 1
            rd, wr, ex = select.select(iw, ow, ew, 3)
            if ex: break
            for fd in rd:
                all = fd.recv(4096)
                if all:
                    sys.stdout.write(all)
                    conn.send(all)
                    count = 0
            if count == max_idling: break
    except:
        print sys.exc_info()
    finally:
        conn.close()
        redir_sock.close()



def main(srv):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((srv[0], srv[1]))
    s.listen(10)
    while 1:
        conn, addr = s.accept()
        print "Connected by", addr
        thread.start_new_thread(Http_Redir2, ((conn, addr),))

if __name__ == "__main__":
    main(local_addr)
